/*
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package botobjects;

import interfaces.BotObject;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import main.CommonMethods;
import main.Constants;
import main.Main;
import main.UserCentral;

import org.apache.log4j.Logger;
import org.jibble.pircbot.Colors;

import tools.StringTools;
import tools.UtopiaTime;

import commandhandlers.SpellsOpsHandler;

import database.DBConnectionFactory;

/**
 * This class represents a duration spell or op
 * 
 * 
 */
public class SpellOp implements BotObject, Comparable<SpellOp> {
   /**
    * Returns a list of spellops; the content of the list depending on the type and args parameters
    * 
    * @param type
    *           Decides what goes in the list
    * @param args
    *           Used to fetch the necessary info to populate the list
    * @return a List of SpellOp objects
    */
   public static List<SpellOp> getSpellOp(final int type, final String... args) {
	  List<SpellOp> out = new LinkedList<SpellOp>();
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 if (type == Constants.SPELLOP_GET_FOR_PLAYER && args.length == 1) {
			ps = DBConnectionFactory
				  .getConnectionHandler()
				  .getConnection()
				  .prepareStatement(
						"SELECT * FROM " + "spellop,kdprovince,province WHERE mainnick = ? AND spellop.province = "
							  + "kdprovince.province AND spellop.province = province.name");
			ps.setString(1, args[0]);
		 } else if (type == Constants.SPELLOP_GET_FOR_PROV && args.length == 1) {
			ps = DBConnectionFactory
				  .getConnectionHandler()
				  .getConnection()
				  .prepareStatement("SELECT * FROM " + "spellop,province WHERE province = ? AND spellop.province = province.name");
			ps.setString(1, args[0]);
		 } else if (type == Constants.SPELLOP_GET_FOR_SPELLOP_FOR_KD && args.length == 2) {
			ps = DBConnectionFactory
				  .getConnectionHandler()
				  .getConnection()
				  .prepareStatement(
						"SELECT * FROM "
							  + "spellop,province WHERE spellop.name = ? AND kdloc = ? AND spellop.province = province.name");
			ps.setString(1, args[0]);
			ps.setString(2, args[1]);
		 } else if (type == Constants.SPELLOP_GET_FOR_SPELLOP_FOR_ALL && args.length == 1) {
			ps = DBConnectionFactory
				  .getConnectionHandler()
				  .getConnection()
				  .prepareStatement(
						"SELECT * FROM " + "spellop,province WHERE spellop.name = ? AND spellop.province = province.name");
			ps.setString(1, args[0]);
		 }
		 if (ps != null) {
			rs = ps.executeQuery();

			while (rs.next()) {
			   out.add(new SpellOp(rs.getString("province"), rs.getString("kdloc"), rs.getString("spellop.name"), rs
					 .getTimestamp("ends").getTime(), ""));
			}
		 }
	  } catch (SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (Exception e) {
		 }
		 try {
			ps.close();
		 } catch (Exception e) {
		 }
	  }
	  return out;
   }

   private String provname = "";
   private String kd = "";
   private String name = "";
   private Long endtime = 0L;

   private String sender = "";

   public SpellOp(final String provname, final String kd, final String name, final Long endtime, final String sender) {
	  this.provname = provname;
	  this.kd = kd;
	  this.name = name;
	  this.endtime = endtime;
	  this.sender = sender;
   }

   /**
    * Compares two spellops based on their end times
    */
   @Override
   public int compareTo(final SpellOp o) {
	  if (endtime < o.getEndtime())
		 return -1;
	  else if (equals(o))
		 return 0;
	  else
		 return 1;
   }

   /**
    * Two spellops are considered equal if they end on the same date, as the only comparison made are to order spellops
    */
   @Override
   public boolean equals(final Object o) {
	  if (o == null)
		 return false;
	  if (o instanceof SpellOp)
		 return endtime.equals(((SpellOp) o).endtime);
	  return false;
   }

   public Long getEndtime() {
	  return endtime;
   }

   @Override
   public List<String> getIRCOutput(final int outputType, final String... args) {
	  List<String> out = new LinkedList<String>();
	  if (StringTools.isNullOrEmpty(getProvname()) || StringTools.isNullOrEmpty(getKd()) || StringTools.isNullOrEmpty(getName())
			|| getSender() == null || getEndtime() == null)
		 return out;
	  String hoursleft = UtopiaTime.compareTimes(getEndtime());
	  if (outputType == Constants.SPELLOP_GET_FOR_PLAYER) {
		 out.add(Colors.RED + CommonMethods.getOwner(getProvname()) + "'s " + Colors.TEAL + getName() + Colors.OLIVE
			   + " ends in " + Colors.BLUE + hoursleft);
	  } else {
		 out.add(Colors.RED + getProvname() + "'s " + Colors.TEAL + getName() + Colors.OLIVE + " ends in " + Colors.BLUE
			   + hoursleft);
	  }
	  return out;
   }

   public String getKd() {
	  return kd;
   }

   public String getName() {
	  return name;
   }

   public String getProvname() {
	  return provname;
   }

   @Override
   public Map<String, Object> getRPCOutput(final int... includes) {
	  Map<String, Object> out = new HashMap<String, Object>();
	  if (StringTools.isNullOrEmpty(getProvname()) || StringTools.isNullOrEmpty(getKd()) || StringTools.isNullOrEmpty(getName())
			|| StringTools.isNullOrEmpty(getSender()) || getEndtime() == null)
		 return out;
	  out.put("Province", getProvname());
	  out.put("KD", getKd());
	  out.put("Name", getName());
	  out.put("End Time", new Date(getEndtime()));
	  out.put("Player", getSender());
	  return out;
   }

   public String getSender() {
	  return sender;
   }

   @Override
   public int hashCode() {
	  assert false : "hashCode not designed";
	  return 42; // any arbitrary constant will do
   }

   /**
    * Prints a save message
    * 
    * @return
    */
   public String printSave() {
	  if (StringTools.isNullOrEmpty(getProvname()) || StringTools.isNullOrEmpty(getKd()) || StringTools.isNullOrEmpty(getName())
			|| StringTools.isNullOrEmpty(getSender()) || getEndtime() == null)
		 return "";
	  if (getKd().equals("(" + Main.getBotSettings().getKdLoc() + ")"))
		 return Colors.TEAL + getName() + Colors.OLIVE + " added. Ends in " + Colors.BLUE + UtopiaTime.compareTimes(getEndtime());
	  else {
		 CommonMethods.addAction(UserCentral.getInstance().getOnlineUser(getSender()), getName());
		 return Colors.TEAL + getName() + Colors.OLIVE + " added for " + Colors.BLUE + getProvname() + " " + getKd()
			   + Colors.OLIVE + ". Ends in " + Colors.BLUE + UtopiaTime.compareTimes(getEndtime());
	  }
   }

   @Override
   public boolean saveToDB() {
	  boolean out = false;
	  String mainnick = UserCentral.getInstance().getOnlineUser(sender);
	  if ("".equals(getProvname())) {
		 if ("".equals(SpellsOpsHandler.getSpellOpTarget(mainnick)))
			return out;
		 else {
			provname = SpellsOpsHandler.getSpellOpTarget(mainnick);
			Province prov = Province.getProvince(provname);
			if (prov == null)
			   return out;
			else {
			   kd = prov.getKd();
			}
		 }
	  } else {
		 if (!"".equals(getKd()) && !CommonMethods.kdExists(getKd())) {
			if (!CommonMethods.addDefaultKD(getKd()))
			   return out;
		 }
		 if ("".equals(CommonMethods.provinceExists(getProvname()))) {
			if (!new Province(getProvname(), getKd(), "", "", "", 0, 0).saveToDB())
			   return out;
		 }
	  }
	  if (StringTools.isNullOrEmpty(getProvname()) || StringTools.isNullOrEmpty(getKd()) || StringTools.isNullOrEmpty(getName())
			|| StringTools.isNullOrEmpty(getSender()) || getEndtime() == null)
		 return out;
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("DELETE FROM spellop WHERE province = ? AND name = ?");
		 ps.setString(1, getProvname());
		 ps.setString(2, getName());
		 ps.executeUpdate();

		 try {
			ps.close();
		 } catch (Exception e) {
		 }

		 ps = DBConnectionFactory.getConnectionHandler().getConnection().prepareStatement("INSERT INTO spellop VALUES(?,?,?)");
		 ps.setString(1, getProvname());
		 ps.setString(2, getName());
		 ps.setTimestamp(3, new Timestamp(getEndtime()));
		 if (ps.executeUpdate() == 1) {
			out = true;
		 }
	  } catch (SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } catch (NumberFormatException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (Exception e) {
		 }
	  }
	  return out;
   }
}
